
// Copyright (C) 2007 Richard Uhler
// This file is part of Esiply.
//
// Esiply is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, Version 2,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef _VALUE_H_
#define _VALUE_H_

// A Value in javascript is an entity that takes on one of nine
// types: Undefined, Null, Boolean, String, etc...

#include <iostream>
//#include <gc_cpp.h>

#include "Expression.h"
#include "ValueType.h"

class Boolean;
class Completion;
class Function;
class List;
class Number;
class Object;
class Reference;
class String;

// A Value is an Expression for convinience and cleanliness of code. It
// just returns itself when evaluated. We see this often in the case
// of literal values: numbers, strings, bools, undefined, null, etc...

typedef Number*(*binary_numberop_t)(Number* lhs, Number* rhs);

class Value : public Expression
{
public:
    Value();
    virtual Value* evaluate(Scope* scope);

    virtual ValueType getType() const = 0;
    virtual Boolean* toBoolean();
    virtual Number* toNumber();
    virtual Object* toObject();
    virtual Value* toPrimitive();
    virtual Value* toPrimitive(ValueType hint);
    virtual String* toString();
    virtual Number* toInteger();
    virtual Number* toInt32();
    virtual Number* toUint32();
    virtual Number* toUint16();

    virtual Value* getValue();
    virtual void putValue(Value* value);

    virtual bool isException() const;

    // Convinience methods for casting. These throw asserts if the type
    // you try to cast to isn't right.
    Object* object() const;
    Number* number() const;
    String* string() const;
    Boolean* boolean() const;
    Function* function() const;
    List* list() const;
    Completion* completion() const;
    Reference* reference() const;

    // operators
    static Boolean* less_than(Value* lhs, Value* rhs);
    static Boolean* equals(Value* lhs, Value* rhs);
    static Value* add(Value* lhs, Value* rhs);
    static Value* subtract(Value* lhs, Value* rhs);
    static Value* multiply(Value* lhs, Value* rhs);
    static Value* divide(Value* lhs, Value* rhs);
    static Value* modulo(Value* lhs, Value* rhs);
    static Value* left_shift(Value* lhs, Value* rhs);
    static Value* right_shift(Value* lhs, Value* rhs);
    static Value* unsigned_right_shift(Value* lhs, Value* rhs);
    static Value* bitwise_and(Value* lhs, Value* rhs);
    static Value* bitwise_or(Value* lhs, Value* rhs);
    static Value* bitwise_xor(Value* lhs, Value* rhs);
    static Boolean* strict_equals(Value* lhs, Value* rhs);

    // Helper function for the operators which expect numbers.
    static Value* number_operate(Value* lhs, Value* rhs, binary_numberop_t op);

private:
    // we shouldn't be copying.
    Value(const Value& rhs);
    virtual Value& operator=(const Value& rhs);
};

// Macro to make it easier for testing for exceptions
#define CHECK_EXCEPTION(x) if ((x)->isException()) return x

#endif//_VALUE_H_

